package com.baimo.support.utils;

import java.text.SimpleDateFormat;
import java.util.concurrent.atomic.AtomicInteger;

public class IdWorker { 
	private final static long twepoch = 1288834974657L; 
 
	private final static long workerIdBits = 5L; 
 
	private final static long datacenterIdBits = 5L; 
 
	private final static long maxWorkerId = -1L ^ (-1L << workerIdBits); 
 
	private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); 
 
	private final static long sequenceBits = 12L; 
 
	private final static long workerIdShift = sequenceBits; 
 
	private final static long datacenterIdShift = sequenceBits + workerIdBits; 
 
	private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; 
	
	private final static long sequenceMask = -1L ^ (-1L << sequenceBits); 
	
	private static long lastTimestamp = -1L; 
	
	
	private long sequence = 0L; 
	private final long workerId; 
	private final long datacenterId; 
	
	public IdWorker(long workerId, long datacenterId) { 
		if (workerId > maxWorkerId || workerId < 0) { 
			throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0"); 
		} 
		if (datacenterId > maxDatacenterId || datacenterId < 0) { 
			throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0"); 
		} 
		this.workerId = workerId; 
		this.datacenterId = datacenterId; 
	}
	
	public synchronized long nextId() { 
		long timestamp = timeGen(); 
		if (timestamp < lastTimestamp) { 
			try { 
				throw new Exception("Clock moved backwards.  Refusing to generate id for "+ (lastTimestamp - timestamp) + " milliseconds"); 
			} catch (Exception e) { 
				e.printStackTrace(); 
			} 
		} 
	
		if (lastTimestamp == timestamp) { 

			sequence = (sequence + 1) & sequenceMask; 
			if (sequence == 0) { 
 
				timestamp = tilNextMillis(lastTimestamp); 
			} 
		} else { 
			sequence = 0; 
		} 
		lastTimestamp = timestamp; 
 
		long nextId = ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; 
		return nextId; 
	} 
	
	private long tilNextMillis(final long lastTimestamp) { 
		long timestamp = this.timeGen(); 
		while (timestamp <= lastTimestamp) { 
			timestamp = this.timeGen(); 
		} 
		return timestamp; 
	} 
	
	private long timeGen() { 
		return System.currentTimeMillis(); 
	}

	public static int Guid=100;
	public static String LOCAL_GUID = getGuid();
	public static String getGuid() {
		
		Guid += 1;

		long now = System.currentTimeMillis();  
 
		SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy");  
  
		String time=dateFormat.format(now);
		String info=now+"";
		int ran=0;
		if(Guid>999){
			Guid=100;    	
		}
		ran=Guid;
				
		return time+info.substring(2, info.length())+ran;  
	}
	public static String getLocalGuId() throws InterruptedException {
		String tmpId = getGuid();
		if(LOCAL_GUID.equals(tmpId)) {
			Thread.sleep(2);
			return getLocalGuId();
		}else {
			LOCAL_GUID = tmpId;
			return tmpId;
		}
	}
	
	
	
    public static void main(String[] args) {
    	for(int i = 0;i<3000;i++) {
        	AtomicInteger counter = new AtomicInteger(0);
        	int it = counter.incrementAndGet();
        	long time = System.currentTimeMillis();
        	System.out.println(time*1000 + it);
    	}

    }

} 